/*
 * 
 * Copyright 2011 visual-analysis-of-cancer.
 * This file is part of visual-analysis-of-cancer.
 * 
 * visual-analysis-of-cancer is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * visual-analysis-of-cancer is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with kOSMik.  If not, see <http://www.gnu.org/licenses/>.
 *  
 * visual-analysis-of-cancer:
 * An tool to analye the WHO and GLOBOCAN cancer data.
 * http://code.google.com/p/visual-analysis-of-cancer/
 * 
 * 
 * 
 * Authors: Erik Sniegula, Johannes Dahlke
 * 
 * Module:  Programming in Processing for Visual Analytics
 * Group:   20
 * 
 * Created: Aug. 2011
 * Version: 1.0
 *
 */
 




package de.fuberlin.processing.who.cancer.gui.detailgraph;

import java.awt.Font;
import java.util.Collection;
import java.util.Observable;
import java.util.Observer;
import java.util.Vector;

import processing.core.PApplet;
import controlP5.ControlP5;
import controlP5.Controller;
import controlP5.ControllerGroup;
import de.fuberlin.processing.who.cancer.data.DBException;
import de.fuberlin.processing.who.cancer.data.Database;
import de.fuberlin.processing.who.cancer.data.DatabaseConnector;
import de.fuberlin.processing.who.cancer.data.DatabaseConnectorImpl;
import de.fuberlin.processing.who.cancer.interaction.LocationBroadcaster;
import de.fuberlin.processing.who.cancer.interaction.LocationModifier;
import de.fuberlin.processing.who.cancer.utils.Fonts;
import de.fuberlin.processing.who.cancer.utils.Test;


public abstract class BarChart extends Controller implements Observer {

	private float left;
	private float top;
	private LocationModifier locationModifier;
	protected Collection<Integer> selectedLocations;
	private int rowHeight = 16;
	private int spaceHeight = 2;
	private int spaceWidth = 5;
	protected DatabaseConnector db;
	
	private String title = "";
	private String leftScala = "";
	private String midScala = "";
	private String rightScala = "";
	protected boolean isLeftOriented = true;
	
	
	public BarChart( ControlP5 theControlP5, ControllerGroup theParent,
			String theName, float theX, float theY, int theWidth, int theHeight) {
		super( theControlP5, theParent, theName, theX, theY, theWidth, theHeight);
		this.left = theX;
		this.top = theY;
		connectToDatabase();
		this.locationModifier = LocationBroadcaster.get();
		this.locationModifier.addObserver(this);
		updateLocations( locationModifier.getLocations());
	}
	
	private void connectToDatabase() {
		try {
			db = Database.get();
		} catch (DBException e) {
			e.printStackTrace();
		}
	}
	
	
	public void setTitle( String title) {
		this.title = title;
	}
	
	
	public void setLeftScala( String leftScala) {
		this.leftScala = leftScala;
	}
	
	
	public void setMidScala( String midScala) {
		this.midScala = midScala;
	}
	
	
	public void setRightScala( String rightScala) {
		this.rightScala = rightScala;
	}
	
	
	public void setLeftOriented() {
		this.isLeftOriented = true;	
		updateScala();
		update();
	}
	
	public void setRightOriented() {
		this.isLeftOriented = false;
		updateScala();
		update();
	}
	
	
	@Override
	public void draw( PApplet p) {
		p.pushStyle();
		if ( height > 20) {
			p.stroke( 0);
			p.fill( 255);
			p.rect( left, top, width, height -20);
			p.strokeWeight( 0.25f);
			float k = width / 9.0f;
			for ( int i = 1; i < 10; i++) {
				p.line( left +i*k, top, left +i*k, top + height -20);
			}
			if ( Test.isAssigned( selectedLocations) ) {
        Vector<Integer> locations = new Vector<Integer>(selectedLocations);
				for ( int i = 0; i < locations.size(); i++) {
					float y = top + 2*i*spaceHeight + spaceHeight +(i*rowHeight);
					if ( y > top + spaceHeight + height -(20 + 2*spaceHeight +rowHeight)) 
						break;
					p.pushMatrix();
					p.translate( left + spaceWidth, y); 
					drawCell( p, locations.get( i), width - spaceWidth*2, rowHeight);
					p.popMatrix();
				}
			}
			
			p.fill( 0);
			// draw title
			p.pushMatrix();
			p.translate( left, top + height -10); 
			drawTitle( p, width, 10);
			p.popMatrix();
			
		  // draw scala
			p.pushMatrix();
			p.translate( left, top + height -20); 
			drawScala( p, width, 10);
			p.popMatrix();
					
		}
		p.popStyle();
	}

	@Override
	public Controller setValue( float theValue) {
		// TODO Auto-generated method stub
		return null;
	}
	
	protected abstract void updateScala();
	
	protected void loadData() {
		updateScala();
	}
	
	protected abstract void drawCell( PApplet theApplet, int locationId, int cellWidth, int cellHeight);
	
	private void drawTitle( PApplet p, int width, int height) {
		p.pushStyle();
		p.textFont( Fonts.getDejavuSans(), 10);
	  float titleWidth = p.textWidth( title);
	  float titleLeft = ( width -titleWidth) / 2;
	  p.text( title, titleLeft, height);
	  p.popStyle();
	}
	
	private void drawScala( PApplet p, int width, int height) {
		p.pushStyle();
		p.textFont( Fonts.getDejavuSans(), 10);
	  float midScalaLen = p.textWidth( midScala);
	  float midOffset = ( width -midScalaLen) / 2;
	  float rightScalaLen = p.textWidth( rightScala);
	  float rightOffset = width -rightScalaLen;
	  p.text( leftScala, 0, 10);
		p.text( midScala, midOffset, 10);
		p.text( rightScala, rightOffset, 10);
		p.popStyle();
	}
	
	
	@Override
	public void update( Observable observable, Object arg) {
		if ( observable instanceof LocationBroadcaster) {
			locationModifier.getLocations();
			Collection<Integer> selectedLocations = locationModifier.getLocations();
			updateLocations( selectedLocations);
		}
	}
	
	
	private void updateLocations( final Collection<Integer> selectedLocations) {
		this.selectedLocations = locationModifier.getLocations();
		loadData();
		update();
	}
	
	public int size() {
		return Test.isAssigned( selectedLocations) ? selectedLocations.size() : 0;
	}

	public int neededHeight() {
		return size()*(rowHeight + 2*spaceHeight) +20;
	}

	
}
